#ifndef __LICH_MD__
#define __LICH_MD__

#include "configure.h"
#include "fs_proto.h"
#include "fileinfo.h"
#include "chunk_proto.h"
#include "chunk.h"
#include "lichstor.h"


inline static void md_initattr(setattr_t *setattr, uint32_t type, uint32_t replica)
{
        memset((void *)setattr, 0x0, sizeof(*setattr));

        setattr->uid.set_it = 1;
        setattr->uid.val = getuid();

        setattr->gid.set_it = 1;
        setattr->gid.val = getgid();

        setattr->mode.set_it = 1;
        if (S_ISREG(type)) {
                setattr->mode.val = 0644;
        } else if (S_ISDIR(type)) {
                setattr->mode.val = 0755;
#if LSV
                setattr->size.set_it = SET_PHYSICAL_SIZE;
#else
                setattr->size.set_it = __SET_PHYSICAL_SIZE;
#endif
                setattr->size.size = FAKE_BLOCK;
        }

        setattr->priority.set_it = 1;
        setattr->priority.val = -1;

        setattr->ec.set_it = 1;
        setattr->ec.ec.plugin = PLUGIN_NULL;
        setattr->ec.ec.tech = TECH_NULL;
        setattr->ec.ec.m = 0;
        setattr->ec.ec.k = 0;

        setattr->atime.set_it = __SET_TO_CLIENT_TIME;
        setattr->atime.time.seconds = gettime();
        setattr->atime.time.nseconds = 0;
        setattr->mtime = setattr->atime;

        if (replica) {
                setattr->replica.set_it = 1;
                setattr->replica.val = replica;
        }
}

inline static void md_info2attr(setattr_t *setattr, const fileinfo_t *fileinfo)
{
        if (fileinfo->priority != -1) {
                setattr->priority.set_it = 1;
                setattr->priority.val = fileinfo->priority;
        }

        if ((fileinfo->attr & __FILE_ATTR_LOCALIZE__)) {
                setattr->localize.set_it = 1;
                setattr->localize.val = 1;
        }

        if ((fileinfo->attr & __FILE_ATTR_MULTPATH__)) {
                setattr->multpath.set_it = 1;
                setattr->multpath.val = 1;
        }

        if ((fileinfo->attr & __FILE_ATTR_WRITEBACK__)) {
                setattr->writeback.set_it = 1;
                setattr->writeback.val = 1;
        }

        if (fileinfo->ec.plugin != PLUGIN_NULL) {
                setattr->ec.set_it = 1;
                setattr->ec.ec = fileinfo->ec;

                setattr->replica.set_it = 1;
                setattr->replica.val = fileinfo->ec.m;
        } else if (fileinfo->repnum_usr != 0) {
                setattr->replica.set_it = 1;
                setattr->replica.val = fileinfo->repnum_usr;
        }

}

inline static void md_info2stat(struct stat *stbuf, const fileinfo_t *fileinfo)
{
        if (fileinfo->id.type == __POOL_CHUNK__) {
                stbuf->st_mode = fileinfo->mode | __S_IFDIR;
        } else {
                stbuf->st_mode = fileinfo->mode | __S_IFREG;
        }

        stbuf->st_atime = fileinfo->atime;
        stbuf->st_mtime = fileinfo->mtime;
        stbuf->st_ctime = fileinfo->ctime;
        stbuf->st_nlink = 1;
        stbuf->st_dev = 0;
        stbuf->st_rdev = 0;
        stbuf->st_ino = fileinfo->id.id;
        stbuf->st_uid = fileinfo->uid;
        stbuf->st_gid = fileinfo->gid;
        if (is_lsv(fileinfo))
            stbuf->st_size = fileinfo->logical_size;
        else if (is_row2(fileinfo))
            stbuf->st_size = fileinfo->logical_size;
        else if (is_row3(fileinfo))
            stbuf->st_size = fileinfo->logical_size;
        else
            stbuf->st_size = fileinfo->size;
        stbuf->st_blocks = _ceil(stbuf->st_size, FAKE_BLOCK);

        DBUG(""CHKID_FORMAT"\n", CHKID_ARG(&fileinfo->id));
}

// ALL exports

int md_init();

int md_root(fileid_t *rootid, const char *pool);
int md_root_del(const char *pool);

// pool

int md_mkpool(const fileid_t *parent, const char *name, const setattr_t *_setattr, chkinfo_t *chkinfo);
int md_mkpool_with_area(const fileid_t *parent, const char *name, const char *site_name, const setattr_t *_setattr, chkinfo_t *chkinfo);
int md_rmpool(const fileid_t *fileid, const char *name);

int md_listpool_open(const fileid_t *dirid, const char *uuid);
int md_listpool(const fileid_t *dirid, const char *uuid, uint64_t offset, void *de, int *delen);
int md_listpool_close(const fileid_t *dirid, const char *uuid);
int md_extend_pool(const fileid_t *poolid);

// volume

int md_mkvol(const fileid_t *parent, const char *name, const char *site_name, const setattr_t *_setattr, chkinfo_t *chkinfo);
int md_mkvolwith(const fileid_t *parent, const char *name, const chkinfo_t *chkinfo);
int md_rmvol(const fileid_t *fileid, const char *name, int force);
int md_cleanup(const fileid_t *fileid, const char *name);

int md_lookup_byname(const char *pool, const fileid_t *parent, const char *name, chkinfo_t *chkinfo, nid_t *parentnid);
int md_lookup_byname1(const fileid_t *parent, const char *name,
                      chkinfo_t *chkinfo, nid_t *parentnid);
int md_stat(const fileid_t *chkid, filestat_t *filestat);
int md_check_ready(const fileid_t *chkid);
int md_isempty(const fileid_t *fileid, int *empty);
int md_getparent(const nid_t *nid, const chkid_t *chkid, chkid_t *parent);

int md_getpool(const fileid_t *chkid, char *pool);
int md_getattr(const fileid_t *chkid, fileinfo_t *fileinfo);
int md_setattr(const fileid_t *chkid, fileinfo_t *fileinfo, const setattr_t *setattr);

int md_rename(const fileid_t *fromdir, const char *fromname,
                  const fileid_t *todir, const char *toname);
int md_rename_lock(const fileid_t *fileid, const fileid_t *src, const char *name, int force);
int md_rename_unlock(const fileid_t *fileid, const chkinfo_t *chkinfo);

int md_allocate(const fileid_t *fileid, const chkid_t *chkid, chkinfo_t *_chkinfo, nid_t *parentnid);
int md_move(const nid_t *_nid, const fileid_t *fileid, const nid_t *dist, int count);
int md_localize(const nid_t *_nid, const fileid_t *fileid, int idx);

// chunk

int md_chunk_getid(const char *pool, const char *path, chkid_t *_chkid);

int md_chunk_getinfo(const char *pool, const fileid_t *parent, const chkid_t *chkid, chkinfo_t *chkinfo, nid_t *parentnid);
int md_chunk_getinfo1(const char *pool, const fileid_t *parent, const fileid_t *chkid,
                      chkinfo_t *chkinfo, nid_t *parentnid);

int md_chunk_allocate(const fileid_t *fileid, const chkid_t *chkid, int chknum, int fill, nid_t *parentnid);

int md_chunk_reject(const char *pool, const fileid_t *parent, const chkid_t *chkid, const nid_t *bad,
                    chkinfo_t *_chkinfo, nid_t *parentnid);

int md_chunk_online(const char *pool, const fileid_t *parent, chkinfo_t *chkinfo);

// 设置副本状态
int md_chunk_set(const fileid_t *parent, const chkid_t *chkid, const nid_t *nid, int status);

// vfm
int md_vfm_set(const volid_t *volid, const chkid_t *chkid, const vfm_t *vfm);
int md_vfm_get(const volid_t *volid, const chkid_t *chkid, vfm_t *vfm);
int md_vfm_cleanup(const fileid_t *fileid);
int md_vfm_stat(const fileid_t *fileid, int *count);

// 设置新的副本集
int md_chunk_move(const nid_t *nid, const chkid_t *parent, const chkid_t *chkid, const nid_t *dist, int dist_count);

// 修复副本集
int md_chunk_check(const nid_t *nid, const fileid_t *fileid, const chkid_t *chkid, int idx, int async, int force, int *oflags);

int md_chunk_update(const char *pool, const fileid_t *parent, const chkinfo_t *_chkinfo, const nid_t *owner, uint64_t info_version);

int md_chunk_setsite(const fileid_t *chkid, const char *site_name);
int md_chunk_setsite_path(const char *pool, const char *path, const char *_site);
int md_chunk_getsite(const char *pool, const fileid_t *chkid, char *site_name);
int md_chunk_getsite_bylocal(char *site_name);
int md_chunk_getsite_byinfo(const char *pool, const fileid_t *chkid, char *site_name);

int md_chunk_table_write(const fileid_t *fileid, const chkid_t *chkid, const buffer_t *buf, uint32_t size, uint64_t offset);
int md_chunk_table_read(const fileid_t *fileid, const chkid_t *chkid, buffer_t *buf, uint32_t size, uint64_t offset);

// snapshot

int md_snapshot_create(const fileid_t *parent, int p, const char *name);
int md_snapshot_create_with_area(const fileid_t *parent, const char *name, int p, const char *_site);
int md_snapshot_remove(const fileid_t *parent, const char *name, int force);

int md_snapshot_listopen(const fileid_t *volid, const char *uuid);
int md_snapshot_list(const fileid_t *volid, const char *uuid, uint64_t offset, void *de, int *delen);
int md_snapshot_listclose(const fileid_t *volid, const char *uuid);
int md_snapshot_check(const fileid_t *, const char *);
int md_snapshot_isempty(const fileid_t *fid, int *empty);

int md_snapshot_protect(const fileid_t *fileid, const snap_protect_param_t on);

int md_snapshot_rollback(const fileid_t *parent, const char *name);
int md_snapshot_flat(const fileid_t *parent, const int idx, int force);
int md_snapshot_updateparent(const fileid_t *parent, const char *name, const uint64_t from);
int md_snapshot_setfrom(const fileid_t *parent, const uint64_t from);
int md_snapshot_last(const fileid_t *parent, nid_t *snapnid, fileid_t *snapid, char *snapname, uint64_t *snap_version);
int md_snapshot_prev(const fileid_t *parent, const fileid_t *snapid, fileid_t *previd, char *name, uint64_t *snap_version);

int md_group_snapshot_create(const fileid_t *fids, const char *name, int count, const char **_site);

// xattr

int md_xattr_set(const nid_t *_nid, const chkid_t *chkid, const char *key,
                 const char *value, int valuelen, int flag);
int md_xattr_remove(const nid_t *nid, const chkid_t *chkid, const char *key);
int md_xattr_list(const nid_t *_nid, const chkid_t *chkid, char *buf, int *buflen);
int md_xattr_get(const nid_t *_nid, const chkid_t *chkid, const char *key,
                 char *value, int *valuelen);

int md_setattr_extend(const fileid_t *fileid, const char *key, const char *value);
int md_getattr_extend(const fileid_t *fileid, const char *key, char *value);
int md_removeattr_extend(const fileid_t *fileid, const char *key);

// connection
int md_connection(const nid_t *nid, const fileid_t *fileid, void *buf, int *count);
int md_check_connection(fileid_t *fileid);

int md_disconnect(const fileid_t *fileid, const nid_t *peer, const char *addr);

#endif
